#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#include "util.h"

int find_string(const char* string, const char* strings[], int size) {
    assert(string != NULL);
    assert(size >= 0);
    int strings_left = size;
    int* matches = (int*) calloc(size, sizeof(int*));
    memset(matches, 0, size * sizeof(int*));
    
    int pos = 0;
    while (strings_left > 0) {
        for (int i = 0; i < size; i++) {
            if (matches[i] == 0) {
                if (strings[i][pos] == string[pos]) {
                    if (string[pos] == '\0') {
                        free(matches);
                        return i;
                    }
                } else {
                    matches[i] = -1;
                    strings_left--;
                }
            }
        }
        if (string[pos] == '\0') {
            break;
        }
        pos++;
    }
    free(matches);
    return -1;
}

char* string_concat(const char* src[]) {
    int length_sum = 0;
    const char** pnt = src;
    while (*pnt != NULL) {
        length_sum += strlen(*pnt);
        pnt++;
    }
    
    char* result = (char*) malloc(length_sum + 1);
    int pos = 0;
    pnt = src;
    while (*pnt != NULL) {
        int len = strlen(*pnt);
        memcpy(result + pos, *pnt, len);
        pos += len;
        pnt++;
    }
    result[length_sum] = '\0';
    return result;
}

char* string_duplicate(const char* src) {
    assert(src != NULL);
    int len = strlen(src);
    char* res = (char*) malloc(len + 1);
    memcpy(res, src, len + 1);
    return res;
}

void curl_common_setup(CURL* curl, const char* portal_host,
    const char* portal_search) {
    const char* referer_str[] = {
        "http://",
        portal_host,
        "/eportal/index.jsp",
        portal_search == NULL ? "" : "?",
        portal_search == NULL ? "" : portal_search,
        NULL
    };
    char* referer = string_concat(referer_str);
    curl_easy_setopt(curl, CURLOPT_REFERER, referer);
    free(referer);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0");
}

static char special_reserved_chars[] = {
    '-', '.', '_', '~',
    /* JavaScript special chars*/
    '!', '\'', '(', ')', '*'
};

static int isReservedChar(char c) {
    if (isdigit(c)) {
        return 1;
    }
    if (isalpha(c)) {
        return 1;
    }
    for (int i = 0; i < sizeof(special_reserved_chars) / sizeof(char); i++) {
        if (c == special_reserved_chars[i]) {
            return 1;
        }
    }
    return 0;
}

void char_to_hex(char code, char* buffer) {
    int digit_first = code / 16;
    int digit_second = code % 16;
    buffer[0] = digit_first < 10 ? '0' + digit_first : 'A' + (digit_first - 10);
    buffer[1] = digit_second < 10 ? '0' + digit_second : 'A' + (digit_second - 10);
}

int char_is_hex(char c) {
    return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}

int hex_to_char(const char* buffer) {
    if (buffer[0] == '\0' || buffer[1] == '\0') {
        return -1;
    }
    if (!char_is_hex(buffer[0]) || !char_is_hex(buffer[1])) {
        return -1;
    }
    int digit_first;
    if (isdigit(buffer[0])) {
        digit_first = buffer[0] - '0';
    } else if (islower(buffer[0])) {
        digit_first = buffer[0] - 'a' + 10;
    } else {
        digit_first = buffer[0] - 'A' + 10;
    }
    int digit_second;
    if (isdigit(buffer[1])) {
        digit_second = buffer[1] - '0';
    } else if (islower(buffer[1])) {
        digit_second = buffer[1] - 'a' + 10;
    } else {
        digit_second = buffer[1] - 'A' + 10;
    }
    return digit_first * 16 + digit_second;
}

char* url_encode_component(const char* string) {
    int encoded_length = 0;
    int string_length = 0;
    const char* pnt = string;
    while (*pnt != '\0') {
        if (isReservedChar(*pnt)) {
            encoded_length += 1;
        } else {
            encoded_length += 3;
        }
        pnt++;
        string_length++;
    }
    
    char* result = (char*) malloc(encoded_length + 1);
    char* write_pnt = result;
    pnt = string;
    while (*pnt != '\0') {
        if (isReservedChar(*pnt)) {
            *(write_pnt++) = *(pnt++);
        } else {
            *(write_pnt++) = '%';
            char_to_hex(*pnt++, write_pnt);
            write_pnt += 2;
        }
    }
    result[encoded_length] = '\0';
    return result;
}
